/**
 * @file vector .h
 * @author your name (you@domain.com)
 * @brief 
 * @version 0.1
 * @date 2024-04-01
 * 
 * @copyright Copyright (c) 2024
 * 
 */
#ifndef JSASM_BASE_VECTOR_H_
#define JSASM_BASE_VECTOR_H_
#include <algorithm>
#include <cstring>
#include <iterator>
#include <limits>
#include <memory>
#include <type_traits>

namespace base {

template <typename T>
class Vector {
    public:
        using value_type = T;
        using iterator = T*;
        using const_iterator = const T*;

        constexpr Vector() : start_(nullptr), length_(0) {}

        constexpr Vector(T* data, size_t length) : start_(data), length_(length) {

        }

        static Vector<T> New(size_t length) {
            return Vector<T>(new T[length], length);
        }

        int length() const {
            //std::numeric_limits<int>::max();
            return static_cast<int>(length_);
        }

        // Returns the length of the vector as a size_t.
        constexpr size_t size() const { return length_; }

        // Returns whether or not the vector is empty.
        constexpr bool empty() const { return length_ == 0; }

        T& operator[](size_t index) const {
            return start_[index];
        }

        const T& at(size_t index) const { return operator[](index); }

        T& first() { return start_[0]; }

        T& last() {
            return start_[length_ - 1];
        }
        
        constexpr T* begin() const { return start_; }

        constexpr T* data() const { return start_; }

        constexpr T* end() const { return start_ + length_; }

        constexpr std::reverse_iterator<T*> rbegin() const {
            return std::make_reverse_iterator(end());
        }

        constexpr std::reverse_iterator<T*> rend() const {
            return std::make_reverse_iterator(begin());
        }

        Vector<T> Clone() const {
            T* result = new T[length_];
            for (size_t i = 0; i < length_; i++) result[i] = start_[i];
            return Vector<T>(result, length_);
        }

        void Dispose() {
            delete[] start_;
            start_ = nullptr;
            length_ = 0;
        }

        Vector<T> operator+(size_t offset) {
            return Vector<T>(start_ + offset, length_ - offset);
        }

        Vector<T> operator+=(size_t offset) {
            start_ += offset;
            length_ -= offset;
            return *this;
        }

        operator Vector<const T>() const { return { start_, length_ }; }

        template <typename S>
        static Vector<T> cast(Vector<S> input) {
            static_assert(std::is_trivial_v<S> && std::is_standard_layout_v<S>);
            static_assert(std::is_trivial_v<T> && std::is_standard_layout_v<T>);

            return Vector<T>(reinterpret_cast<T*>(input.begin()), input.size() * sizeof(S) / sizeof(T));
        }

        bool operator==(const Vector<T>& other) const {
            return std::equal(begin(), end(), other.begin(), other.end());
        }

        bool operator!=(const Vector<T>& other) const {
            return !operator==(other);
        }

        template <typename TT = T>
        std::enable_if_t<!std::is_const_v<TT>, bool> operator==(
            const Vector<const T>& other) const {
            return std::equal(begin(), end(), other.begin(), other.end());
        }

        template <typename TT = T>
        std::enable_if_t<!std::is_const_v<TT>, bool> operator!=(
            const Vector<const T>& other) const {
            return !operator==(other);
        }
    
    private:
        T* start_;
        size_t length_;
};

} // namespace base

#endif // JSASM_BASE_VECTOR_H_